<template>
  <div ref="tags" class="tags" :style="{backgroundColor, paddingLeft: booleanArrowShow ? arrowWidth : 0, paddingRight: booleanArrowShow ? arrowWidth : 0}">
    <span @click="arrowLeftClick" v-if="booleanArrowShow" class="c-tags-arrow c-tags-arrow-prev" :class="{'c-tags-arrow--disabled': !isLeftClick}" :style="{border, borderColor, color: isLeftClick ? iconColor : iconColorNotAllowed, backgroundColor, width: arrowWidth}">
      <i class="el-icon-d-arrow-left"></i>
    </span>
    <span @click="arrowRightClick" v-if="booleanArrowShow" class="c-tags-arrow c-tags-arrow-next" :class="{'c-tags-arrow--disabled': !isRightClick}" :style="{border, borderColor, color: isRightClick ? iconColor : iconColorNotAllowed, backgroundColor, width: arrowWidth}">
      <i class="el-icon-d-arrow-right"></i>
    </span>
    <div ref="c-tags" class="c-tags" :style="{backgroundColor, border, borderColor, width: '100%', height: '100%', overflow: 'hidden' }">
      <div class="c-tags__translate" v-if="tabList" :style="{backgroundColor, transform: `translate(${xMoveWidth}px, 0px)`, width: tagsWidth, height: '100%'}">
        <el-tag
          ref="tag"
          :key="index"
          :style="{fontSize, color: tag.isActive ? activeFontColor : fontColor, backgroundColor, borderRadius, borderRightWidth, borderColor, height: '100%'}"
          v-for="(tag, index) in tabList"
          :effect="tagEffect"
          :disable-transitions="false"
          @click.stop="clickTag(tag)"
          @contextmenu.prevent.native="rightShow(index)">
          <div class="c-tags-wrap">
            <custom-tooltip  :style="{maxWidth: maxTabWidth}" :is-show-copy="false" :value="tag.name"></custom-tooltip>
            <!-- <span>{{tag.name}}</span> -->
            <c-icon
              v-if="tag.closeable"
              icon="el-icon-close"
              :backgroundColor="backgroundColor"
              :hoverColor="activeCloseColor"
              :color="closeColor"
              @click="remove(tag)"
            />
          </div>
          <el-dropdown  style="top: -100%;" placement="bottom-start" ref="dropdown" trigger="contextmenu" @command="clickTagMenu" :show-timeout="100">
            <div style="height: 0;"></div>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item v-if="tag.isActive" :command="{key:'update-tab', tag}">刷新</el-dropdown-item>
              <el-dropdown-item v-if="!tag.closeable" :command="{key:'remove-tab', tag}">关闭当前</el-dropdown-item>
              <el-dropdown-item :command="{key:'close-other-tab', tag}" >关闭其他</el-dropdown-item>
              <el-dropdown-item :command="{key:'close-all-tab', tag}">关闭全部</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </el-tag>
      </div>
    </div>
  </div>
</template>

<script>
import CIcon from './cIcon'
import CustomTooltip from '../../components/custom-tooltip'
import { cloneDeep, debounce, throttle } from 'lodash';
export default {
  name: 'MTabsNav',
  components: {CIcon, CustomTooltip},
  props: {
    tabList: null,
    configure: null, // 可配置样式 时间等
    useArrow: {
      type: Boolean,
      default: true
    },
    tagEffect: {
      type: String,
      default: 'light'
    }
  },
  data() {
    return {
      xMoveWidth: 0,
      tagsWidth: 'auto',
      tagsWrapWidth: 'auto',
      maxTabWidth: '80px',
      isArrowShow: false,
      arrowWidth: '33px', // 可配置
      activeFontColor: '#4D84FF', // 可配置
      fontSize: '12px', // 可配置
      fontColor: '#666666', // 可配置
      closeColor: '#999', // 可配置
      activeCloseColor: 'red', // 可配置
      backgroundColor: '#ffffff', // 可配置
      borderColor: ' #E6E6E6', // 可配置
      borderRadius: '0', // 可配置
      border: '1px solid', // 可配置
      borderRightWidth: '1px', // 可配置
      iconColor: '#333', // 可配置
      iconColorNotAllowed: '#999', // 可配置
      scrollTime: 200, // 可配置单位ms
      scrollWaitTime: 100 // 可配置单位ms
    }
  },
  computed: {
    isLeftClick() {
      return this.xMoveWidth < 0
    },
    isRightClick() {
      return this.xMoveWidth + parseInt(this.tagsWidth) > parseInt(this.tagsWrapWidth)
    },
    booleanArrowShow() {
      return this.useArrow && this.isArrowShow
    },
    tagData() {
      return cloneDeep(this.tabList)
    }
  },
  created() {
    this.setConfigure(this.configure)
    this.deResetTagsPosition = debounce(this.resetTagsPosition, this.scrollWaitTime)
    this.thResetTagsPosition = throttle(this.resetTagsPosition, this.scrollWaitTime)
    this.deScroll = debounce(this.scroll, this.scrollWaitTime)
  },
  mounted() {
    window.addEventListener('resize', () => {
      // console.log('tags')
      this.thResetTagsPosition(this.tagData)
    })
  },
  watch: {
    tagData: {
      handler(val, oldVal) {
        this.$nextTick(() => {
          this.resetTagsPosition(val, oldVal)
        })
      },
      deep: true,
      immediate: true
    }
  },
  methods: {
    setConfigure(val) {
      // console.log(val, 'configure')
      this.arrowWidth = val.arrowWidth || this.arrowWidth
      this.activeFontColor = val.activeFontColor || this.activeFontColor
      this.fontSize = val.fontSize || this.fontSize
      this.fontColor = val.fontColor || this.fontColor
      this.closeColor = val.closeColor || this.closeColor
      this.activeCloseColor = val.activeCloseColor || this.activeCloseColor
      this.backgroundColor = val.backgroundColor || this.backgroundColor
      this.borderColor = val.borderColor || this.borderColor
      this.border = val.border || this.border
      this.borderRadius = val.borderRadius || this.borderRadius
      this.iconColor = val.iconColor || this.iconColor
      this.iconColorNotAllowed = val.iconColorNotAllowed || this.iconColorNotAllowed
      this.scrollTime = val.scrollTime || this.scrollTime
      this.scrollWaitTime = val.scrollWaitTime || this.scrollWaitTime
      this.maxTabWidth = val.maxTabWidth || this.maxTabWidth
    },
    resetTagsPosition(val, oldVal) {
      let index = val.findIndex(item => item.isActive)
      let oldIndex = oldVal && oldVal.findIndex(item => item.isActive)
      let [wrapWidth, tagsWrapWidth, tagsWidth] = this.getWrapWidthList()
      let tagsWidthList = this.$refs['tag'].map(it => {
        return it.$el.offsetWidth
      })
      this.tagsWidth = tagsWidth + 'px'
      this.tagsWrapWidth = tagsWrapWidth + 'px'
      // console.log(wrapWidth, tagsWidth)
      this.isArrowShow = wrapWidth < tagsWidth
      if (!this.isArrowShow) {
        this.xMoveWidth = 0
        return
      }
      if (this.isTranslateX(tagsWidthList, index, tagsWrapWidth, this.xMoveWidth)) {
        let xMoveWidth = this.getTranslateX(tagsWidthList, index, tagsWrapWidth)
        this.deScroll(this.xMoveWidth, xMoveWidth)
      }
    },
    
    /**
    * @description 滑动方法
    * @param {number} from 起始位置
    * @param {number} to 目标位置
    * @param {number} time 滑动时长
    */
    scroll (from, to, time = this.scrollTime) {
      // console.log(from, to)
      if (from === to) {
        return
      }
      let isToDown = Boolean(from > to)
      let isToUp = Boolean(from < to)
      // 页面刷新频率一般60次/s
      let count = time * 60 / 1000
      let step = (to - from) / count
      let _this = this
      try {
        let timer = window.requestAnimationFrame(function fn(){
          if (isToDown) {
            // console.log(_this.xMoveWidth)
            if(_this.xMoveWidth > to){
              _this.xMoveWidth = _this.xMoveWidth + step
              timer = requestAnimationFrame(fn);
            }else{
              _this.xMoveWidth = to
              window.cancelAnimationFrame(timer);
            }
          }
          if (isToUp) {
            if(_this.xMoveWidth < to){
              _this.xMoveWidth = _this.xMoveWidth + step
              timer = requestAnimationFrame(fn);
            }else{
              _this.xMoveWidth = to
              window.cancelAnimationFrame(timer);
            }
          }
        })
      } catch (error) {
        // 没有就不做动画了也可以对requestAnimationFrame和cancelAnimationFrame进行兼容处理
        this.xMoveWidth = to
      }
    },
    arrowLeftClick() {
      let [, tagsWrapWidth, tagsWidth] = this.getWrapWidthList()
      let xMoveWidth = this.getArrowTranslateX(this.xMoveWidth + tagsWrapWidth, tagsWrapWidth - tagsWidth)
      this.deScroll(this.xMoveWidth, xMoveWidth)
    },
    arrowRightClick() {
      let [, tagsWrapWidth, tagsWidth] = this.getWrapWidthList()
      let xMoveWidth = this.getArrowTranslateX(this.xMoveWidth - tagsWrapWidth, tagsWrapWidth - tagsWidth)
      this.deScroll(this.xMoveWidth, xMoveWidth)
    },
    // 定位右侧优先 左侧次之
    getTranslateX(list, active, tagsWrapWidth) {
      let [leftWidth, leftWidthHasActive, tagsWidth] = this.getActiveWidthList(list, active)
      // 右侧
      if (leftWidthHasActive > tagsWrapWidth) {
        return tagsWrapWidth - leftWidthHasActive
      } else if (leftWidth < tagsWrapWidth && leftWidth + tagsWrapWidth < tagsWidth) {
        return 0 - leftWidth
      } else {
        return 0
      }
    },
    // 定位右侧优先 左侧次之
    getArrowTranslateX(targetValue, minValue, maxValue = 0) {
      if (targetValue >= minValue && targetValue <= maxValue) {
        return targetValue
      }
      if (targetValue > maxValue) {
        return maxValue
      } else {
        return minValue
      }
    },
    // 是否需要移动判断
    isTranslateX(list, active, tagsWrapWidth, xMoveWidth) {
      let activeRightPosition = 0 - xMoveWidth + tagsWrapWidth
      let activeLeftPosition = 0 - xMoveWidth
      let [leftWidth, leftWidthHasActive, tagsWidth] = this.getActiveWidthList(list, active)
      // 1.左边距判断 2.右边距判断 3.整体判断
      return activeLeftPosition >= leftWidthHasActive || activeRightPosition <= leftWidth || tagsWidth + xMoveWidth < tagsWrapWidth
    },
    // 获取宽度集合
    getActiveWidthList(list, active) {
      let leftWidth = 0
      let leftWidthHasActive = 0
      let tagsWidth = 0
      list.forEach((item, index) => {
        tagsWidth = tagsWidth + item
        if (index < active) {
          leftWidth = leftWidth + item
          leftWidthHasActive = leftWidthHasActive + item
        }
        if (index === active) {
          leftWidthHasActive = leftWidthHasActive + item
        }
      })
      // console.log(leftWidth, leftWidthHasActive, tagsWidth)
      // [左边距，左边距含选中项，总宽度]
      return [leftWidth, leftWidthHasActive, tagsWidth]
    },
    // 获取宽度集合
    getWrapWidthList() {
      let wrapWidth = this.$refs['tags'].offsetWidth
      let tagsWrapWidth = this.$refs['c-tags'].offsetWidth === wrapWidth ? this.$refs['c-tags'].offsetWidth - this.arrowWidth * 2 : this.$refs['c-tags'].offsetWidth
      let tagsWidthList = this.$refs['tag'].map(it => {
        return it.$el.offsetWidth
      })
      let tagsWidth = tagsWidthList.reduce((pre, next) => {
        return pre + next
      })
      // [滑动爷爷级盒子宽度，滑动父级盒子宽度， 滑动盒子自己宽度]
      // console.log([wrapWidth, tagsWrapWidth, tagsWidth])
      return [wrapWidth, tagsWrapWidth, tagsWidth]
    },
    /**
     * tag相关操作
     * removeTab--删除选中tag页签
     * clickTag--切换tag页签
     * rightShow--右键展示下拉menu
     * clickTagMenu--tag下拉menu单项选中事件
     * closeOtherTab--关闭其他页签
     * updateTag--刷新页面
     * closeAllTab--关闭所有tag页签
     */
    clickTagMenu (e) {
      // console.log(e, 'e')
      this.$emit(e.key, e.tag)
    },
    remove (e) {
      // console.log(e)
      this.$emit('remove-tab', e)
    },
    clickTag (e) {
      this.$emit('click', e)
    },
    rightShow (index) {
      // console.log(this.$refs['dropdown'][index], index)
      this.$refs['dropdown'][index].show()
    }
  }

}
</script>

<style lang="less" scoped>
.tags {
  position: relative;
  width: 100%;
  height:100%;
  box-sizing: border-box;
  transition-property: padding;
  transition-duration: 0.1s;
  transition-timing-function: linear;
  transition-delay: 0.2s;
  /* Safari */
  -webkit-transition-property:padding;
  -webkit-transition-duration:0.1s;
  -webkit-transition-timing-function:linear;
  -webkit-transition-delay:0.2s;
}
.c-tags {
  box-sizing: border-box;
  /deep/.el-tag {
    border-width: 0;
    cursor: pointer;
  }
}
.c-tags__translate {
  position: relative;
  white-space: nowrap;
}
.c-tags-wrap {
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
.c-tags-arrow {
  font-size: 16px;
  z-index:1;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  position: absolute;
  cursor: pointer;
  :hover {
    color: #4D84FF;
  }
}
.c-tags-arrow-prev{
  left: 0;
}
.c-tags-arrow.c-tags-arrow--disabled{
  cursor: not-allowed;
}
.c-tags-arrow-next{
  right: 0;
}
</style>